type TouchCallback = (value: any, event: TouchEvent) => void;

interface Binding {
  value: any; // This should be a more specific type if possible
}

class VueTouch {
  private obj: HTMLElement;
  private binding: Binding;
  private touchType: string;
  private vueTouches: { x: number; y: number };
  private vueMoves: boolean;
  private vueLeave: boolean;
  private vueCallBack: TouchCallback;
  private time: NodeJS.Timeout | null = null;
  private longTouch: boolean;

  constructor(el: HTMLElement, binding: any, type: string) {
    this.obj = el;
    this.binding = binding;
    this.touchType = type;
    this.vueTouches = { x: 0, y: 0 };
    this.vueMoves = true;
    this.vueLeave = true;
    this.longTouch = false;
    this.vueCallBack = binding;
    this.obj.addEventListener("touchstart", (e) => this.start(e), false);
    this.obj.addEventListener("touchend", (e) => this.end(e), false);
    this.obj.addEventListener("touchmove", (e) => this.move(e), false);
  }
  private start(e: TouchEvent) {
    this.vueMoves = true;
    this.vueLeave = true;
    this.longTouch = true;
    this.vueTouches = {
      x: e.changedTouches[0].clientX,
      y: e.changedTouches[0].clientY,
    };

    this.time = setTimeout(() => {
      if (this.vueLeave && this.vueMoves) {
        if (this.touchType === "longtap") {
          this.vueCallBack(this.binding.value, e);
        }
        this.longTouch = false;
      }
    }, 1000);
  }

  private end(e: TouchEvent) {
    clearTimeout(this.time!); // Assert that time is not null because it's set in start()

    const disX = e.changedTouches[0].clientX - this.vueTouches.x;
    const disY = e.changedTouches[0].clientY - this.vueTouches.y;

    if (Math.abs(disX) > 10 || Math.abs(disY) > 100) {
      if (this.touchType === "swipe") {
        this.vueCallBack(this.binding.value, e);
      }
      if (Math.abs(disX) > Math.abs(disY)) {
        // 判断是横向滑动还是纵向滑动
        if (disX > 30) {
          this.touchType == "swiperight" &&
            this.vueCallBack(this.binding.value, e); // 右滑
        }
        if (disX < -30) {
          this.touchType == "swipeleft" &&
            this.vueCallBack(this.binding.value, e); // 左滑
        }
      } else {
        if (disY > 30) {
          this.touchType == "swipedown" &&
            this.vueCallBack(this.binding.value, e); // 下滑
        }
        if (disY < -30) {
          this.touchType == "swipeup" &&
            this.vueCallBack(this.binding.value, e); // 上滑
        }
      }
    } else if (this.longTouch && this.vueMoves) {
      if (this.touchType === "tap") {
        this.vueCallBack(this.binding.value, e);
      }
      this.vueLeave = false;
    }
  }

  private move(e: TouchEvent) {
    this.vueMoves = false;
  }
}

export default VueTouch;
